/**
 * Licensed under the Apache License, Version 2.0 (the "License"); you may
 * not use this file except in compliance with the License. You may obtain
 * a copy of the License at
 * 
 *         http://www.apache.org/licenses/LICENSE-2.0
 *         
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License. Unless required by applicable law or
 * agreed to in writing, software distributed under the License is
 * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the specific
 * language governing permissions and limitations under the License.
 */
package org.rhok.ncn.common;

import android.telephony.SignalStrength;

/**
 * Utility class for converting a signal strength object in to the number
 * of 'bars' that is displayed.  Lots of inspiration from the Android source
 * code here.
 * @author bschwartz
 *
 */
public class SignalCalculator {

	// @formatter:off
	public static final int SIGNAL_EXCELLENT = 4; // hack for disabling formatter
	public static final int SIGNAL_GOOD      = 3; // on older Eclipse versions
	public static final int SIGNAL_OK        = 2; //
	public static final int SIGNAL_POOR      = 1; //
	public static final int SIGNAL_NONE      = 0; //
	// @formatter:on
	
	public static int getLevel(SignalStrength ss) {
		if (ss.isGsm()) {
			return getGSMLevel(ss);
		} else {
			int cdmaLevel = getCDMALevel(ss);
			int evdoLevel = getEVDOLevel(ss);
			
			// @formatter:off
			
			return (evdoLevel == SIGNAL_NONE) ? cdmaLevel                      : //
				   (cdmaLevel == SIGNAL_NONE) ? evdoLevel                      : //
					                            Math.min(evdoLevel, cdmaLevel) ; //
			
			// @formatter:on
		}
		
	}

	private static int getGSMLevel(SignalStrength ss) {
		int asu = ss.getGsmSignalStrength();
		
		// @formatter:off
		
		return (asu <= 2 || asu == 99) ? SIGNAL_NONE      : //
			   (asu >= 12)             ? SIGNAL_EXCELLENT : //
			   (asu >= 8)              ? SIGNAL_GOOD      : //
			   (asu >= 5)              ? SIGNAL_OK        : //
				                         SIGNAL_POOR      ; //
		
		// @formatter:on
	}
	
	private static int getCDMALevel(SignalStrength ss) {
		int cdmaDB = ss.getCdmaDbm();
		int cdmaEcio = ss.getCdmaEcio();
				
		
		// @formatter:off
		int dbLevel = (cdmaDB >= -75)  ? SIGNAL_EXCELLENT : //
			          (cdmaDB >= -85)  ? SIGNAL_GOOD      : // 
			          (cdmaDB >= -95)  ? SIGNAL_OK        : //
			          (cdmaDB >= -110) ? SIGNAL_POOR      : //
			        	                 SIGNAL_NONE      ; //
		
		
		int ecioLevel = (cdmaEcio >= -90)  ? SIGNAL_EXCELLENT : //
			            (cdmaEcio >= -110) ? SIGNAL_GOOD      : //
			            (cdmaEcio >= -130) ? SIGNAL_OK        : //
			            (cdmaEcio >= -150) ? SIGNAL_POOR      : //
			            	                 SIGNAL_NONE      ; //
		
		// @formatter:on
		
		return Math.min(dbLevel, ecioLevel);
	}
	
	private static int getEVDOLevel(SignalStrength ss) {
		int dbm = ss.getEvdoDbm();
		int snr = ss.getEvdoSnr();
		
		// @formatter:off
		
		int dbLevel = (dbm >= -65)  ?  SIGNAL_EXCELLENT  : //
			          (dbm >= -75)  ?  SIGNAL_GOOD       : //
			          (dbm >= -90)  ?  SIGNAL_OK         : //
			          (dbm >= -105) ?  SIGNAL_POOR       : //
			        	               SIGNAL_NONE       ; //
		
		
		int snrLevel = (snr >= 7) ? SIGNAL_EXCELLENT : //
			           (snr >= 5) ? SIGNAL_GOOD      : //
			           (snr >= 3) ? SIGNAL_OK        : //
			           (snr >= 2) ? SIGNAL_POOR      : //
			        	            SIGNAL_NONE      ; //
		
		// @formatter:on
		
		
		return Math.min(dbLevel, snrLevel);
	}
}
